{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3-1,低阶API示范\n",
    "\n",
    "下面的范例使用TensorFlow的低阶API实现线性回归模型。\n",
    "\n",
    "低阶API主要包括张量操作，计算图和自动微分。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "\n",
    "#打印时间分割线\n",
    "@tf.function\n",
    "def printbar():\n",
    "    ts = tf.timestamp()\n",
    "    today_ts = ts%(24*60*60)\n",
    "\n",
    "    hour = tf.cast(today_ts//3600+8,tf.int32)%tf.constant(24)\n",
    "    minite = tf.cast((today_ts%3600)//60,tf.int32)\n",
    "    second = tf.cast(tf.floor(today_ts%60),tf.int32)\n",
    "    \n",
    "    def timeformat(m):\n",
    "        if tf.strings.length(tf.strings.format(\"{}\",m))==1:\n",
    "            return(tf.strings.format(\"0{}\",m))\n",
    "        else:\n",
    "            return(tf.strings.format(\"{}\",m))\n",
    "    \n",
    "    timestring = tf.strings.join([timeformat(hour),timeformat(minite),\n",
    "                timeformat(second)],separator = \":\")\n",
    "    tf.print(\"==========\"*8,end = \"\")\n",
    "    tf.print(timestring)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 样本数量\n",
    "n =400\n",
    "\n",
    "# 生成测试用数据集\n",
    "X = tf.random.uniform([n, 2], minval=-10, maxval=10)\n",
    "w0 = tf.constant([[2.0], [-1.0]])\n",
    "b0 = tf.constant(3.0)\n",
    "Y = X@w0 + b0 + tf.random.normal([n, 1], mean=0.0, stddev=2.0)# @表示矩阵乘法,增加正态扰动"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================================================================22:49:58\n",
      "epoch = 1000 ; loss = 2.70946407\n",
      "w = [[1.98515093]\n",
      " [-1.03169119]]\n",
      "b = 2.02254653\n",
      "\n",
      "================================================================================22:50:00\n",
      "epoch = 2000 ; loss = 2.1017797\n",
      "w = [[1.99002635]\n",
      " [-1.02539611]]\n",
      "b = 2.77152085\n",
      "\n",
      "================================================================================22:50:01\n",
      "epoch = 3000 ; loss = 2.01909518\n",
      "w = [[1.99182439]\n",
      " [-1.02307415]]\n",
      "b = 3.04779363\n",
      "\n",
      "================================================================================22:50:02\n",
      "epoch = 4000 ; loss = 2.00784397\n",
      "w = [[1.99248791]\n",
      " [-1.02221823]]\n",
      "b = 3.14970684\n",
      "\n",
      "================================================================================22:50:03\n",
      "epoch = 5000 ; loss = 2.00631309\n",
      "w = [[1.99273252]\n",
      " [-1.02190089]]\n",
      "b = 3.18729782\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 使用动态图调试\n",
    "\n",
    "w = tf.Variable(tf.random.normal(w0.shape))\n",
    "b = tf.Variable(0.0)\n",
    "\n",
    "def train(epoches):\n",
    "    for epoch in tf.range(1, epoches+1):\n",
    "        with tf.GradientTape() as tape:\n",
    "            # 正向传播求损失\n",
    "            Y_hat = X@w + b\n",
    "            loss = tf.squeeze(tf.transpose(Y-Y_hat)@(Y-Y_hat)/(2.0*n))\n",
    "            # tf.squeeze 给定张量输入，此操作返回相同类型的张量，并删除所有尺寸为1的尺寸。\n",
    "        # 反向传播求梯度\n",
    "        dloss_dw, dloss_db = tape.gradient(loss, [w, b])\n",
    "        # 梯度下降法更新参数\n",
    "        w.assign(w - 0.001 * dloss_dw)\n",
    "        b.assign(b - 0.001 * dloss_db)\n",
    "        if epoch % 1000 == 0:\n",
    "            printbar()\n",
    "            tf.print(\"epoch =\", epoch, \"; loss =\", loss)\n",
    "            tf.print(\"w =\", w)\n",
    "            tf.print(\"b =\", b)\n",
    "            tf.print(\"\")\n",
    "train(5000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================================================================22:50:15\n",
      "epoch = 1000  loss = 2.70483422\n",
      "w = [[1.98517644]\n",
      " [-1.03165841]]\n",
      "b = 2.02645826\n",
      "\n",
      "================================================================================22:50:15\n",
      "epoch = 2000  loss = 2.10114884\n",
      "w = [[1.99003589]\n",
      " [-1.02538383]]\n",
      "b = 2.77296615\n",
      "\n",
      "================================================================================22:50:15\n",
      "epoch = 3000  loss = 2.0190084\n",
      "w = [[1.99182796]\n",
      " [-1.02306986]]\n",
      "b = 3.04833055\n",
      "\n",
      "================================================================================22:50:15\n",
      "epoch = 4000  loss = 2.00783205\n",
      "w = [[1.9924891]\n",
      " [-1.02221668]]\n",
      "b = 3.14990139\n",
      "\n",
      "================================================================================22:50:16\n",
      "epoch = 5000  loss = 2.00631142\n",
      "w = [[1.992733]\n",
      " [-1.0219003]]\n",
      "b = 3.18736935\n",
      "\n"
     ]
    }
   ],
   "source": [
    "##使用autograph机制转换成静态图加速\n",
    "w = tf.Variable(tf.random.normal(w0.shape))\n",
    "b = tf.Variable(0.0)\n",
    "\n",
    "@tf.function\n",
    "def train(epoches):\n",
    "    for epoch in tf.range(1,epoches+1):\n",
    "        with tf.GradientTape() as tape:\n",
    "            #正向传播求损失\n",
    "            Y_hat = X@w + b\n",
    "            loss = tf.squeeze(tf.transpose(Y-Y_hat)@(Y-Y_hat))/(2.0*n)   \n",
    "\n",
    "        # 反向传播求梯度\n",
    "        dloss_dw,dloss_db = tape.gradient(loss,[w,b])\n",
    "        # 梯度下降法更新参数\n",
    "        w.assign(w - 0.001*dloss_dw)\n",
    "        b.assign(b - 0.001*dloss_db)\n",
    "        if epoch%1000 == 0:\n",
    "            printbar()\n",
    "            tf.print(\"epoch =\",epoch,\" loss =\",loss,)\n",
    "            tf.print(\"w =\",w)\n",
    "            tf.print(\"b =\",b)\n",
    "            tf.print(\"\")\n",
    "train(5000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
